#include"graph.h"
#include"../../util.h"

QueryGraph::QueryGraph(){}

QueryGraph::QueryGraph(iostream *input)
{
	string line;
	vector<string> v;
	while(!input->eof())
	{
		getline(*input, line);
		v.push_back(line);
	}
	for(int i = 0; i < v.size(); ++ i)
	{
		string &node_s = v[i];
		int del = node_s.find(":");
		string node = node_s.substr(0, del);
		add_node(Query(node));
	}
	for(int i = 0; i < v.size(); ++ i)
	{
		string &node_s = v[i];
		int del = node_s.find(":");
		QueryNode &node1 = (*graph.find(node_s.substr(0, del))).second;
		string neig_s = node_s.substr(del + 1, node_s.length() - del - 1);
		vector<string> neig = util::tokenize_h(neig_s, " | ");
		for(int j = 0; j < neig.size(); ++ j)
		{
			QueryNode &node2 = (*graph.find(neig[j])).second;
			add_edge(node1, node2);
		}
	}
}

void QueryGraph::add_node(Query &query)
{
	graph.insert(pair<string, QueryNode>(query.name, QueryNode(query)));
}

void QueryGraph::add_node(QueryNode node)
{
	graph.insert(pair<string, QueryNode>(node.query.name, node));
}

void QueryGraph::add_edge(QueryNode &n1, QueryNode &n2)
{
	n1.add_edge(n2);
	n2.add_edge(n1);
}

QueryNode QueryGraph::get_node(string name)
{
	return (*graph.find(name)).second;
}
#define BATCH 2000
int b_count = 0;
void QueryGraph::update_edge(EdgeChecker &checker)
{
	map<string, QueryNode>::iterator graph_itr1, graph_itr2;
	for(graph_itr1 = graph.begin(); graph_itr1 != graph.end(); ++ graph_itr1)
	{
		if(b_count++ %BATCH == 0)
			cout << ".";
		QueryNode &node1 = (*graph_itr1).second;
		for(graph_itr2 = graph.begin(); graph_itr2 != graph.end(); ++ graph_itr2)
		{
			QueryNode &node2 = (*graph_itr2).second;
			if(checker.satisfied(node1, node2))
				add_edge(node1, node2);
		}
	}
}

void QueryGraph::flood(vector<vector<string>> &groups)
{
	map<string, QueryNode>::iterator itr;
	set<string> visited;
	for(itr = graph.begin(); itr != graph.end(); ++ itr)
	{
		vector<string> v;
		search((*itr).second, v, visited);
		if(v.size() > 0){
			groups.push_back(v);
		}
	}
}

void QueryGraph::search(QueryNode &seed, vector<string> &elem, set<string> &visited)
{
	if(visited.find(seed.query.name) == visited.end())
	{
		elem.push_back(seed.query.name);
		visited.insert(seed.query.name);
		for(int i = 0; i < elem.size(); ++ i)
		{
			QueryNode &node = get_node(elem[i]);
			for(map<string, QueryNode&>::iterator itr = node.adj_list.begin(); 
					itr != node.adj_list.end(); 
					++ itr)
				if(visited.find((*itr).first) == visited.end())
				{
					visited.insert((*itr).first);
					elem.push_back((*itr).first);
				}
		}
	}
}